package com.xiaochen.manager.service.impl;

import com.xiaochen.common.exception.XiaoChenException;
import com.xiaochen.manager.mapper.SysMenuMapper;
import com.xiaochen.manager.mapper.SysRoleMenuMapper;
import com.xiaochen.manager.mapper.SysRoleUserMapper;
import com.xiaochen.manager.service.SysMenuService;
import com.xiaochen.manager.service.SysRoleMenuService;
import com.xiaochen.manager.utils.MenuHelper;
import com.xiaochen.model.entity.system.SysMenu;
import com.xiaochen.model.entity.system.SysUser;
import com.xiaochen.model.vo.common.ResultCodeEnum;
import com.xiaochen.model.vo.system.SysMenuVo;
import com.xiaochen.utils.AuthContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.LinkedList;
import java.util.List;

@Service
public class SysMenuServiceImpl implements SysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * 获取所有菜单
     * @return
     */
    @Override
    public List<SysMenu> findNodes() {
        // 1.查询所有的菜单
        List<SysMenu> sysMenuList = sysMenuMapper.findNodes();
        if (CollectionUtils.isEmpty(sysMenuList)){
            return null;
        }
        // 2.调用工具类的方法,把返回的菜单进行组装成要求的数据格式
        List<SysMenu> treeList = MenuHelper.buildTree(sysMenuList);

        return treeList;
    }

    /**
     * 添加菜单
     * @param sysMenu
     */
    @Override
    public void addSysMenu(SysMenu sysMenu) {
        sysMenuMapper.addSysMenu(sysMenu);

        // 当我们新添加菜单的时候,需要将全选的(is_half)这个属性变为半开状态 1,不让他全选
        // 直接调用下面的这个 (1.工具方法)
        updateSysRoleMenu(sysMenu);
    }

    /**
     *  1.工具方法
     * 新增子菜单时,需要将父菜单的is_half属性变为半开状态
     * @param sysMenu
     */
    private void updateSysRoleMenu(SysMenu sysMenu) {
        // 获取当前菜单的父菜单
        SysMenu parentMenu = sysMenuMapper.selectParentMenu(sysMenu.getId());
        // 设置父菜单的is_half属性为1
        if (parentMenu != null){
            sysRoleMenuMapper.updateSysRoleMenuIsHalf(parentMenu.getId());

            // 递归调用(避免菜单有多层)
            updateSysRoleMenu(parentMenu);
        }
    }

    /**
     * 修改菜单
     * @param sysMenu
     */
    @Override
    public void updateSysMenu(SysMenu sysMenu) {
       sysMenuMapper.updateSysMenu(sysMenu);
    }

    /**
     * 删除菜单
     * @param id
     *
     * 注意:如果是简单的删除最下层的子菜单,允许直接删除,
     *      但是,如果要删除父菜单,需要判断他的下面是否还有子菜单,如果有子菜单,不允许删除
     *      没有子菜单,才允许删除
     */
    @Transactional
    @Override
    public void removeById(Long id) {
        // 1.判断当前菜单下面是否有子菜单,如果有子菜单,不允许删除
       int count = sysMenuMapper.selectCountById(id);
       if (count > 0){
           throw new XiaoChenException(ResultCodeEnum.NODE_ERROR);
       }
       sysMenuMapper.removeById(id);
    }

    /**
     * 根据id查询菜单
     * @param id
     * @return
     */
    @Override
    public SysMenu findById(Long id) {
        return sysMenuMapper.findById(id);
    }

    /**
     * 根据用户ID查询用户可操作的菜单
     * @return
     */
    @Override
    public List<SysMenuVo> findMenusByUserId() {
        // 1.获取到当前用户的ID(可以直接从线程里面直接拿,或者从redis里面拿)
        SysUser sysUser = AuthContextUtil.get();
        Long userId = sysUser.getId();

        // 2.根据用户ID查询可以操作的菜单
        List<SysMenu> sysMenuList = sysMenuMapper.findMenusByUserId(userId);

        // 3.把菜单进行组装成树形结构并返回,可以直接调用菜单的工具类进行组装
        List<SysMenu> sysMenus = MenuHelper.buildTree(sysMenuList);

        // 4.返回的类型是List<SysMenuVo>,需要调用下面的工具方法进行转换
        List<SysMenuVo> sysMenuVos = this.buildMenus(sysMenus);

        return sysMenuVos;
    }

    /**
     * 工具方法
     * 将List<SysMenu>对象转换成List<SysMenuVo>对象
     */
    private List<SysMenuVo> buildMenus(List<SysMenu> menus) {

        List<SysMenuVo> sysMenuVoList = new LinkedList<SysMenuVo>();
        for (SysMenu sysMenu : menus) {
            SysMenuVo sysMenuVo = new SysMenuVo();
            sysMenuVo.setTitle(sysMenu.getTitle());
            sysMenuVo.setName(sysMenu.getComponent());
            List<SysMenu> children = sysMenu.getChildren();
            if (!CollectionUtils.isEmpty(children)) {
                sysMenuVo.setChildren(buildMenus(children));
            }
            sysMenuVoList.add(sysMenuVo);
        }
        return sysMenuVoList;
    }
}
